今天選擇的題目因為都沒有太困難,所以會一次寫兩題。
第一題,看到題目,知道要找到遺失的鑰匙,並且提示告訴我們,會用到 decompiler。
hint:Download and try to decompile the file.
依照題目,下載給予的檔案,得到一個 java compile 過後的 class 檔。
$ ls -l
total 12
-rw-r--r-- 1 root root 4443 Aug 2 06:00 README.txt
-rw-rw-r-- 1 user user 2036 Mar 16 2023 SafeOpener.class
用 file
和 exiftool
查看詳細資料,沒有發現什麼特別的。
$ file SafeOpener.class
SafeOpener.class: compiled Java class data, version 52.0 (Java 1.8)
$ exiftool SafeOpener.class
ExifTool Version Number : 12.40
File Name : SafeOpener.class
Directory : .
File Size : 2036 bytes
File Modification Date/Time : 2023:03:16 03:15:29+00:00
File Access Date/Time : 2024:08:02 06:01:58+00:00
File Inode Change Date/Time : 2024:08:02 06:01:05+00:00
File Permissions : -rw-rw-r--
File Type : Mach-O fat binary executable
File Type Extension :
MIME Type : application/octet-stream
CPU Count : 52
執行檔案後,會發現有三次輸入密碼的機會,隨便輸入,得到一些亂碼。
$ java SafeOpener
Enter password for the safe: 123
MTIz
Password is incorrect
You have 2 attempt(s) left
Enter password for the safe: 111
MTEx
Password is incorrect
You have 1 attempt(s) left
Enter password for the safe: 222
MjIy
Password is incorrect
You have 0 attempt(s) left
根據提示,於是乎直接用 Decompiler,把 class 檔還原成原始的 java 檔。可以發現 flag 就在 opensafe 的函式裡。在這裡我選擇使用線上的 java decompiler ( .JAR and .Class to Java decompiler )。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Base64;
import java.util.Base64.Encoder;
public class SafeOpener {
public static void main(String[] args) throws IOException {
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
Encoder encoder = Base64.getEncoder();
String encodedkey = "";
String key = "";
for(int i = 0; i < 3; ++i) {
System.out.print("Enter password for the safe: ");
key = keyboard.readLine();
encodedkey = encoder.encodeToString(key.getBytes());
System.out.println(encodedkey);
boolean isOpen = openSafe(encodedkey);
if (isOpen) {
break;
}
System.out.println("You have " + (2 - i) + " attempt(s) left");
}
}
public static boolean openSafe(String password) {
String encodedkey = "picoCTF{SAf3_0p3n3rr_y0u_solv3d_it_5bfbd6f1}";
if (password.equals(encodedkey)) {
System.out.println("Sesame open");
return true;
} else {
System.out.println("Password is incorrect\n");
return false;
}
}
}
繼續下一題,題目需求要找 password,並且沒有提示。
老樣子,先用 ls
看下載了甚麼,發現得到一個未知檔案 ret。
$ ls -l
total 28
-rw-r--r-- 1 root root 4443 Aug 2 06:00 README.txt
-rw-rw-r-- 1 user user 16888 Mar 16 2023 ret
接著用 file
查看詳細資料,發現是執行檔。
$ file ret
ret: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=64856d07d138e412faf30b9722d92f507e3b5c9c, for GNU/Linux 3.2.0, not stripped
於是試著執行題目給予的檔案,程式會要求輸入密碼來解鎖,我們先隨便填入。
$ ./ret
-bash: ./ret: Permission denied
$ chmod +x ret
$ ./ret
Enter the password to unlock this file: 123
You entered: 123
Access denied
因為 ret 是 elf file ,所以使用 readelf
,檢視 ret 檔案詳情。
先用查看 header 裡有沒有甚麼資訊,結果沒有甚麼發現。
$ readelf -h ret
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x10e0
Start of program headers: 64 (bytes into file)
Start of section headers: 14904 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30
於是我查看 Symbol ,並且可以從 symbol table 知道執行了什麼。
並且可以看到第 36 行看到執行了 ret.c 的檔案,第 56 行也可以看到有執行 strcmp 的函式,於是可知 ret 檔案裡應該含有 password。
$ readelf -s ret
Symbol table '.dynsym' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __[...]@GLIBC_2.4 (3)
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND [...]@GLIBC_2.2.5 (2)
7: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __[...]@GLIBC_2.7 (4)
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMC[...]
10: 0000000000000000 0 FUNC WEAK DEFAULT UND [...]@GLIBC_2.2.5 (2)
Symbol table '.symtab' contains 69 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000318 0 SECTION LOCAL DEFAULT 1 .interp
2: 0000000000000338 0 SECTION LOCAL DEFAULT 2 .note.gnu.property
3: 0000000000000358 0 SECTION LOCAL DEFAULT 3 .note.gnu.build-id
4: 000000000000037c 0 SECTION LOCAL DEFAULT 4 .note.ABI-tag
5: 00000000000003a0 0 SECTION LOCAL DEFAULT 5 .gnu.hash
6: 00000000000003c8 0 SECTION LOCAL DEFAULT 6 .dynsym
7: 00000000000004d0 0 SECTION LOCAL DEFAULT 7 .dynstr
8: 0000000000000594 0 SECTION LOCAL DEFAULT 8 .gnu.version
9: 00000000000005b0 0 SECTION LOCAL DEFAULT 9 .gnu.version_r
10: 00000000000005f0 0 SECTION LOCAL DEFAULT 10 .rela.dyn
11: 00000000000006b0 0 SECTION LOCAL DEFAULT 11 .rela.plt
12: 0000000000001000 0 SECTION LOCAL DEFAULT 12 .init
13: 0000000000001020 0 SECTION LOCAL DEFAULT 13 .plt
14: 0000000000001080 0 SECTION LOCAL DEFAULT 14 .plt.got
15: 0000000000001090 0 SECTION LOCAL DEFAULT 15 .plt.sec
16: 00000000000010e0 0 SECTION LOCAL DEFAULT 16 .text
17: 0000000000001348 0 SECTION LOCAL DEFAULT 17 .fini
18: 0000000000002000 0 SECTION LOCAL DEFAULT 18 .rodata
19: 00000000000020a4 0 SECTION LOCAL DEFAULT 19 .eh_frame_hdr
20: 00000000000020e8 0 SECTION LOCAL DEFAULT 20 .eh_frame
21: 0000000000003d98 0 SECTION LOCAL DEFAULT 21 .init_array
22: 0000000000003da0 0 SECTION LOCAL DEFAULT 22 .fini_array
23: 0000000000003da8 0 SECTION LOCAL DEFAULT 23 .dynamic
24: 0000000000003f98 0 SECTION LOCAL DEFAULT 24 .got
25: 0000000000004000 0 SECTION LOCAL DEFAULT 25 .data
26: 0000000000004010 0 SECTION LOCAL DEFAULT 26 .bss
27: 0000000000000000 0 SECTION LOCAL DEFAULT 27 .comment
28: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
29: 0000000000001110 0 FUNC LOCAL DEFAULT 16 deregister_tm_clones
30: 0000000000001140 0 FUNC LOCAL DEFAULT 16 register_tm_clones
31: 0000000000001180 0 FUNC LOCAL DEFAULT 16 __do_global_dtors_aux
32: 0000000000004010 1 OBJECT LOCAL DEFAULT 26 completed.8061
33: 0000000000003da0 0 OBJECT LOCAL DEFAULT 22 __do_global_dtor[...]
34: 00000000000011c0 0 FUNC LOCAL DEFAULT 16 frame_dummy
35: 0000000000003d98 0 OBJECT LOCAL DEFAULT 21 __frame_dummy_in[...]
36: 0000000000000000 0 FILE LOCAL DEFAULT ABS ret.c
37: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
38: 00000000000021ec 0 OBJECT LOCAL DEFAULT 20 __FRAME_END__
39: 0000000000000000 0 FILE LOCAL DEFAULT ABS
40: 0000000000003da0 0 NOTYPE LOCAL DEFAULT 21 __init_array_end
41: 0000000000003da8 0 OBJECT LOCAL DEFAULT 23 _DYNAMIC
42: 0000000000003d98 0 NOTYPE LOCAL DEFAULT 21 __init_array_start
43: 00000000000020a4 0 NOTYPE LOCAL DEFAULT 19 __GNU_EH_FRAME_HDR
44: 0000000000003f98 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_
45: 0000000000001000 0 FUNC LOCAL DEFAULT 12 _init
46: 0000000000001340 5 FUNC GLOBAL DEFAULT 16 __libc_csu_fini
47: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
48: 0000000000004000 0 NOTYPE WEAK DEFAULT 25 data_start
49: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5
50: 0000000000004010 0 NOTYPE GLOBAL DEFAULT 25 _edata
51: 0000000000001348 0 FUNC GLOBAL HIDDEN 17 _fini
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __stack_chk_fail[...]
53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5
54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_mai[...]
55: 0000000000004000 0 NOTYPE GLOBAL DEFAULT 25 __data_start
56: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strcmp@@GLIBC_2.2.5
57: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
58: 0000000000004008 0 OBJECT GLOBAL HIDDEN 25 __dso_handle
59: 0000000000002000 4 OBJECT GLOBAL DEFAULT 18 _IO_stdin_used
60: 00000000000012d0 101 FUNC GLOBAL DEFAULT 16 __libc_csu_init
61: 0000000000004018 0 NOTYPE GLOBAL DEFAULT 26 _end
62: 00000000000010e0 47 FUNC GLOBAL DEFAULT 16 _start
63: 0000000000004010 0 NOTYPE GLOBAL DEFAULT 26 __bss_start
64: 00000000000011c9 250 FUNC GLOBAL DEFAULT 16 main
65: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __isoc99_scanf@@[...]
66: 0000000000004010 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__
67: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMC[...]
68: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@[...]
接著用 strings
把 ret 裡可列印的文字列出,找到 flag。
$ strings ret | grep 'pico'
picoCTF{H
Password correct, please see flag: picoCTF{3lf_r3v3r5ing_succe55ful_d7b14d43}
小結:
練習 java decompiler,並且知道從 elf 檔案中的 symbol table 推敲出有關檔案的線索。